home *** CD-ROM | disk | FTP | other *** search
- /*
- File: HandyWindow.c
-
- Description:
- HandyWindow.c implements the routines used for drawing the windows
- displayed by this application.
-
- Copyright:
- © Copyright 2000 Apple Computer, Inc. All rights reserved.
-
- Disclaimer:
- IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
- ("Apple") in consideration of your agreement to the following terms, and your
- use, installation, modification or redistribution of this Apple software
- constitutes acceptance of these terms. If you do not agree with these terms,
- please do not use, install, modify or redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and subject
- to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
- copyrights in this original Apple software (the "Apple Software"), to use,
- reproduce, modify and redistribute the Apple Software, with or without
- modifications, in source and/or binary forms; provided that if you redistribute
- the Apple Software in its entirety and without modifications, you must retain
- this notice and the following text and disclaimers in all such redistributions of
- the Apple Software. Neither the name, trademarks, service marks or logos of
- Apple Computer, Inc. may be used to endorse or promote products derived from the
- Apple Software without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or implied,
- are granted by Apple herein, including but not limited to any patent rights that
- may be infringed by your derivative works or by other works in which the Apple
- Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
- WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
- (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Change History (most recent first):
- Tue, Feb 8, 2000 -- created
- */
-
-
-
-
-
-
-
- #include "HandyWindow.h"
- #include "SampleUtils.h"
-
- #include <Resources.h>
- #include <StdDef.h>
- #include <string.h>
- #include <Sound.h>
- #include <TextUtils.h>
- #include <Controls.h>
- #include <ControlDefinitions.h>
- #include <Script.h>
- #include <OSUtils.h>
- #include <PLStringFuncs.h>
-
-
- /* constants used to define the image size. */
- #define kBoxSize 80 /* size of color swatches */
- #define kLineSize 2 /* pensize used to draw the boxes */
- #define kPatchSize (kBoxSize + 2) /* color swatch size with border */
- #define kColumnCount 16 /* number of columns of color swatches */
- #define kRowCount 16 /* number of rows of color swatches */
- #define kImageWidth (kPatchSize * kColumnCount) /* total width of the image */
- #define kImageHeight (kPatchSize * kRowCount) /* total height of the image */
- #define kTimerDisplayWidth 100 /* width of timer display area */
-
- /* resource ID numbers for the STR# resource used for
- storing window title strings.*/
- enum {
- kHandyWindowStrings = 128,
- kHandyWindowTitle = 1,
- kHandyWindowSlowTitle = 2
- };
-
-
- /* some ascii codes for special keys on the US keyboard. we use these codes
- in the HandyWindowKey for dispatching keydown events to the scrolling
- routines. */
- enum {
- SOH = 1, /* HOME KEY*/
- EOT = 4, /* END KEY*/
- VT = 11, /* PAGEUP KEY*/
- FF = 12, /* PAGEDOWN KEY*/
- FS = 28, /* LEFT ARROW KEY */
- GS = 29, /* RIGHT ARROW KEY */
- RS = 30, /* UP ARROW KEY */
- US = 31 /* DOWN ARROW KEY */
- };
-
-
-
- /* the HandyWindowRecord type is used for storing information related
- to each HandyWindow. We use these records to store references
- to the scroll bars, and the window's activation state. Also, we store
- a pointer to the window in this structure. In this sample, we use this
- as the key value for finding a given window's HandyWindowRecord record. */
- typedef struct HandyWindowStruct HandyWindowRecord;
- typedef HandyWindowRecord *HandyWindowPtr;
- struct HandyWindowStruct {
- HandyWindowPtr prev, next; /* pointers for our list of handy window records */
- WindowPtr theWindow; /* a pointer to our handy window */
- ControlHandle hScroll, vScroll; /* the horizontal and vertical scroll bars */
- Boolean isActive; /* the window's activation state */
- Boolean useSlowDrawing; /* if true, then add delays while drawing */
- };
-
-
-
- /* gHWFirst and gHWLast are the first and last pointers in a
- linked list of HandyWindowRecord records. */
- static HandyWindowPtr gHWFirst = NULL, gHWLast = NULL;
-
-
-
-
- /* ScrollRectInBlack since the background for our image is black, it would
- be desirable that during scrolling operations the scrolled in area should
- be drawn 'black' instead of the default white colour. To make this happen,
- se set the background colour to black before calling scroll rect. ScrollRectInBlack
- is the same as calling ScrollRect except it scrolls in a black area rather than
- a white one. This helps avoid unnecessary white to black flickering during scrolling
- operations. */
- static void ScrollRectInBlack(const Rect* r, short dh, short dv, RgnHandle updateRgn) {
- RGBColor rgbSave, rgbBlack = { 0x0000, 0x0000, 0x0000 };
- /* save the pen state and background colour */
- GetBackColor(&rgbSave);
- /* set the background colour to black */
- RGBBackColor(&rgbBlack);
- /* scroll the bits */
- ScrollRect(r, dh, dv, updateRgn);
- /* restore the background colour */
- RGBBackColor(&rgbSave);
- }
-
-
-
- /* FindHandyWindow iterates through the list of open handy windows
- looking for a HandyWindowRecord containing a window pointer
- matching the theWindow. If one is found, a pointer to the
- HandyWindowRecord is returned. If there is no HandyWindowRecord
- record for the window in the list of open handy windows, then
- NULL is returned. */
- static HandyWindowPtr FindHandyWindow(WindowPtr theWindow) {
- HandyWindowPtr rover;
- for (rover = gHWFirst; rover != NULL; rover = rover->next)
- if (rover->theWindow == theWindow)
- return rover;
- return NULL;
- }
-
-
-
- /* NewHandyWindowRec allocates a new HandyWindowRecord record,
- adds it to the list of open handy windows, and returns a pointer
- to it. If there is not enough memory to complete the allocation
- request, this routine will return NULL. */
- static HandyWindowPtr NewHandyWindowRec(WindowPtr theWindow) {
- HandyWindowPtr local;
- local = (HandyWindowPtr) NewPtr(sizeof(HandyWindowRecord));
- if (local == NULL)
- return NULL;
- else {
- local->theWindow = theWindow;
- local->prev = local->next = NULL;
- if (gHWFirst == NULL) {
- gHWFirst = gHWLast = local;
- } else {
- local->next = gHWFirst;
- gHWFirst->prev = local;
- gHWFirst = local;
- }
- }
- return local;
- }
-
-
-
- /* DisposeHandyWindowRec removes the HandyWindowRecord
- from the linked list of open handy windows and deallocates
- the storage it occupies. */
- static void DisposeHandyWindowRec(HandyWindowPtr hwRec) {
- if (hwRec->next != NULL)
- hwRec->next->prev = hwRec->prev;
- else gHWLast = hwRec->prev;
- if (hwRec->prev != NULL)
- hwRec->prev->next = hwRec->next;
- else gHWFirst = hwRec->next;
- DisposePtr((Ptr) hwRec);
- }
-
-
-
- /* DrawTimer draws the time tickcount in the bottom left corner of the window.
- This little timer display allows you to monitor redraw times during
- scrolling and update operations. As you will notice, the strategy of
- only redrawing squares that will actually appear on the screen greatly
- reduces the amount of processor time spent in the drawing routine during
- scrolling and update operations.
-
- To draw the entire image contains 256 squares that would require
- a total of 256 ticks (4:16 Seconds) to draw when slow drawing
- is turned on. As you will notice, because of the 'draw only what needs
- to be drawn strategy', timings are much than 4:16 Seconds. */
- static void DrawTimer(CGrafPtr wPort, HandyWindowPtr handp, unsigned long tickcount) {
- Rect windowBounds, timerRect;
- RgnHandle clipsave;
- FontInfo fin;
- unsigned long seconds, sixtieths;
- Str255 title, temp;
-
- /* set up for drawing */
- GetClip((clipsave = NewRgn()));
- SetPort(wPort);
- UseThemeFont(kThemeSmallSystemFont, smSystemScript);
- GetFontInfo(&fin);
- GetPortBounds( wPort, &windowBounds);
- SetRect( &timerRect, windowBounds.left, windowBounds.bottom-15, windowBounds.left+kTimerDisplayWidth, windowBounds.bottom+1);
- timerRect.top += 1;
- /* set the clip region */
- ClipRect(&timerRect);
- EraseRect(&timerRect);
- /* calculate the string to display */
- seconds = tickcount/60;
- sixtieths = tickcount%60;
- NumToString(seconds, title);
- PLstrcat(title, "\p:");
- NumToString(sixtieths, temp);
- if (temp[0] == 1) PLstrcat(title, "\p0");
- PLstrcat(title, temp);
- PLstrcat(title, "\p Seconds");
- /* display the string, centered. */
- MoveTo((timerRect.right + timerRect.left - StringWidth(title)) / 2, (timerRect.bottom + timerRect.top - (fin.ascent + fin.descent))/2 + fin.ascent);
- DrawString(title);
- /* if we're not active, gray it out. */
- if ( ! handp->isActive)
- GrayOutBox(&timerRect);
- /* restore and return. */
- SetClip(clipsave);
- DisposeRgn(clipsave);
- }
-
-
-
- /* DrawHandyWindowImage is called to re-draw the contents of the window. To optimize
- drawing performance this routine limits the drawing routines it calls to only those
- ones that will have a visual result appearing on the screen. To do this, it calculates
- the intersection of the grafport's visRgn, clipRgn, and the *bounds parameter and
- tests to see if what it is about to draw resides in this region before performing
- the actual drawing operations. Since the scrolling routines set the clip region to
- the region returned by ScrollRect, this improves scrolling performance dramatically
- by limiting the drawing operation to only the part of the image scrolled into view.*/
- static void DrawHandyWindowImage(CGrafPtr wPort, Rect *bounds, HandyWindowPtr handp) {
- RgnHandle clipsave, temp, exposedBits;
- short x, y, index, hposition, vposition;
- Rect box, steps, nameplate;
- RGBColor theColor, savedColor;
- RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF }, rgbBlack = { 0x0000, 0x0000, 0x0000 };
- PenState ps;
- Str255 titleStr, tempStr;
- FontInfo fin;
- CTabHandle clut;
- Pattern blackPen;
- unsigned long startTicks, stopTicks;
- /* start the timer */
- startTicks = TickCount();
- /* set up locals */
- hposition = GetControlValue(handp->hScroll);
- vposition = GetControlValue(handp->vScroll);
- index = 0;
- temp = NewRgn();
- clipsave = NewRgn();
- exposedBits = NewRgn();
- clut = GetCTable(72);
- /* calculate content region */
- SetPort(wPort);
- UseThemeFont(kThemeSystemFont, smSystemScript);
- GetFontInfo(&fin);
- GetForeColor(&savedColor);
- SetOrigin(0, 0);
- GetClip(clipsave);
- /* calculate the region of the content that needs to
- be redrawn. Here, this is the intersection of the content
- area, the current clipping region, and the window's visRgn. */
- RectRgn(exposedBits, bounds);
- /* intersect with the clip region */
- SectRgn(clipsave, exposedBits, exposedBits);
- /* intersect with the visible region */
- GetPortVisibleRegion(wPort, temp);
- SectRgn(temp, exposedBits, exposedBits);
- /* only draw, if there's actually something to draw... */
- if ( ! EmptyRgn(exposedBits) ) {
- /* offset the region to it's location in the contents.
- We do this explicitly because although SetOrigin will move
- the portRect and visRgn, it will not move the clipRgn. */
- OffsetRgn(exposedBits, hposition, vposition);
- /* set the origin and clipping region */
- SetOrigin(hposition, vposition);
- SetClip(exposedBits);
- /* set up for drawing */
- GetPenState(&ps);
- PenSize(kLineSize, kLineSize);
- PenMode(patCopy);
- PenPat(GetQDGlobalsBlack(&blackPen));
- RGBForeColor(&rgbBlack);
- RGBBackColor(&rgbWhite);
- /* erase the background *black* */
- PaintRgn(exposedBits);
- /* iterate through rows and columns */
- for (y=0; y<kColumnCount; y++)
- for (x=0; x<kRowCount; x++, index++) {
- /* calculate the location for this color swatch */
- SetRect(&box, 0, 0, kBoxSize, kBoxSize);
- OffsetRect(&box, x*kPatchSize + 1, y*kPatchSize + 1);
-
- /* only draw this item if the drawing operation will have
- some noticable effect on the screen. Overall, this will save
- some time as we're not doing any of the following drawing
- or calculation operations. */
- RectRgn(temp, &box);
- SectRgn(exposedBits, temp, temp);
- if ( EmptyRgn(temp) )
- continue;
-
- /* set the colour */
- theColor = (**clut).ctTable[ index ].rgb;
- RGBForeColor(&theColor);
- /* draw an x in the box */
- MoveTo(box.left, box.top);
- LineTo(box.right - kLineSize, box.bottom - kLineSize);
- MoveTo(box.right - kLineSize, box.top);
- LineTo(box.left, box.bottom - kLineSize);
-
-
- /* for an illustration of how drawing only the exposed
- area can affect timing, uncomment the following line. */
-
- /* the following line is used to slow down drawing
- to simulate a complex drawing task. given that the default
- size of a window will contain 6 X 4 squares, it will
- take at the very least 24 ticks (nearly half a second)
- to redraw the entire window. But, since during scrolling
- operations only the part of the image that needs to be
- redrawn is being drawn, this doesn't really matter. */
- if (handp->useSlowDrawing) {
- unsigned long finalTicks;
- Delay(1, &finalTicks);
- }
-
- /* draw some rescinding frames */
- steps = box;
- while ( ! EmptyRect(&steps)) {
- FrameRect(&steps);
- InsetRect(&steps, kLineSize + 1, kLineSize + 1);
- }
- /* calculate the cell title */
- NumToString(x, titleStr);
- PLstrcat(titleStr, "\p, ");
- NumToString(y, tempStr);
- PLstrcat(titleStr, tempStr);
- /* calculate a box for the title */
- SetRect(&nameplate, 0, 0,
- StringWidth(titleStr) + kLineSize*6,
- fin.ascent + fin.descent + kLineSize*2);
- /* center it in the color swatch */
- OffsetRect(&nameplate,
- (box.right + box.left - nameplate.right) / 2,
- (box.bottom + box.top - nameplate.bottom) / 2);
- /* erase it and draw a frame */
- EraseRect(&nameplate);
- FrameRect(&nameplate);
- /* draw the text in black and white */
- RGBForeColor(&rgbBlack);
- MoveTo(nameplate.left + kLineSize*3, nameplate.top + fin.ascent + kLineSize);
- DrawString(titleStr);
- }
-
- /* reset the origin and clipping region */
- SetPort(wPort);
- SetOrigin(0, 0);
- SetClip(clipsave);
- }
- /* clean up */
- RGBForeColor(&savedColor);
- DisposeRgn(clipsave);
- DisposeRgn(exposedBits);
- DisposeRgn(temp);
- SetPenState(&ps);
- DisposeCTable(clut);
- /* stop the timer */
- stopTicks = TickCount();
- DrawTimer(wPort, handp, stopTicks - startTicks);
- }
-
-
-
- /* IsHandyWindow returns true if the window pointer
- in the HandyWindow parameter is not NULL and
- points to the about box. */
- Boolean IsHandyWindow(WindowPtr theWindow) {
- return (FindHandyWindow(theWindow) != NULL);
- }
-
-
-
- /* GetHandyWindowGrowLimits sets the sizerect rectangle parameter
- to values appropriate for passing to the GrowWindow routine. */
- OSErr GetHandyWindowGrowLimits(WindowPtr theWindow, Rect *sizerect) {
- HandyWindowPtr handp;
- /* get our window globals */
- handp = FindHandyWindow(theWindow);
- if (handp == NULL) return paramErr;
- SetRect(sizerect, 128, 64, kImageWidth+15, kImageWidth+15);
- return noErr;
- }
-
-
-
- /* HandyWindowSizeChanged should be called whenever the size of a window
- created by OpenHandyWindow has been changed by either a call to
- ZoomWindow or SizeWindow. */
- OSErr HandyWindowSizeChanged(WindowPtr theWindow) {
- HandyWindowPtr handp;
- Rect wRect, hsRect, vsRect, contentRect, timerRect;
- CGrafPtr wPort;
- short hmax, vmax;
- RgnHandle invalidRegion;
-
- /* get our window globals */
- handp = FindHandyWindow(theWindow);
- if (handp == NULL) return paramErr;
- /* set up locals */
- invalidRegion = NewRgn();
- SetPort((wPort = GetWindowPort(theWindow)));
- GetPortBounds( wPort, &wRect);
- contentRect = wRect;
- contentRect.right -= 15;
- contentRect.bottom -= 15;
- /* accumulate the old scroll bar and timer rectangles into the update region */
- RgnUnionRect(invalidRegion, GetControlBounds(handp->hScroll, &hsRect));
- SetRect( &timerRect, 0, hsRect.top, kTimerDisplayWidth, hsRect.bottom);
- RgnUnionRect(invalidRegion, &timerRect);
- RgnUnionRect(invalidRegion, GetControlBounds(handp->vScroll, &vsRect));
- /* calculate the boxes */
- SetRect( &timerRect, wRect.left, wRect.bottom-15, wRect.left+kTimerDisplayWidth, wRect.bottom+1);
- SetRect( &hsRect, wRect.left+kTimerDisplayWidth, wRect.bottom-15, wRect.right-14, wRect.bottom+1);
- SetRect( &vsRect, wRect.right-15, wRect.top-1, wRect.right+1, wRect.bottom-14);
- /* reposition the scroll bars */
- SetControlBounds( handp->hScroll, &hsRect);
- SetControlBounds( handp->vScroll, &vsRect);
- vsRect.bottom += 15; /* include the grow box */
- RgnUnionRect(invalidRegion, &timerRect);
- RgnUnionRect(invalidRegion, &hsRect);
- RgnUnionRect(invalidRegion, &vsRect);
- /* set the horizontal scroll bar maximum and value */
- hmax = kImageWidth - contentRect.right;
- if (hmax < 0) hmax = 0;
- if (GetControlValue(handp->hScroll) > hmax) {
- SetControlValue(handp->hScroll, hmax);
- RgnUnionRect(invalidRegion, &contentRect);
- }
- SetControlMaximum(handp->hScroll, hmax);
- SetControlViewSize(handp->hScroll, kImageWidth);
- /* set the vertical scroll bar maximum and value */
- vmax = kImageWidth - contentRect.bottom;
- if (vmax < 0) vmax = 0;
- if (GetControlValue(handp->vScroll) > vmax) {
- SetControlValue( handp->vScroll, vmax);
- RgnUnionRect(invalidRegion, &contentRect);
- }
- SetControlMaximum(handp->vScroll, vmax);
- SetControlViewSize(handp->vScroll, kImageWidth);
- /* announce the accumulated update region */
- InvalWindowRgn(theWindow, invalidRegion);
- DisposeRgn(invalidRegion);
- return noErr;
- }
-
-
-
- /* OpenHandyWindow opens a handy window using the WIND resource
- with the windowID ID. If successful, OpenHandyWindow returns a
- pointer to the newly created window. */
- WindowPtr OpenHandyWindow(short windowID, Boolean drawSlow) {
- Rect wRect, hsRect, vsRect;
- HandyWindowPtr handp;
- WindowPtr theWindow;
- ControlHandle hscroll, vscroll;
- Str255 title;
- /* set up locals */
- handp = NULL;
- theWindow = NULL;
- hscroll = vscroll = NULL;
- /* get the window */
- theWindow = GetNewCWindow(windowID, NULL, (WindowPtr)(-1));
- if (theWindow == NULL) goto bail;
- handp = NewHandyWindowRec(theWindow);
- if (handp == NULL) goto bail;
- /* set up the zoom size */
- SetWindowStandardStateSize(theWindow, kImageWidth+15, kImageWidth+15);
- /* create the scroll bars */
- GetPortBounds(GetWindowPort(theWindow), &wRect);
- SetRect(&hsRect, wRect.left, wRect.bottom-15, wRect.right-14, wRect.bottom+1);
- SetRect(&vsRect, wRect.right-15, wRect.top-1, wRect.right+1, wRect.bottom-14);
- hscroll = NewControl(theWindow, &hsRect, "\p", true, 0, 0, 100, kControlScrollBarLiveProc, (long) handp);
- if (hscroll == NULL) goto bail;
- HiliteControl(hscroll, 255);
- vscroll = NewControl(theWindow, &vsRect, "\p", true, 0, 0, 100, kControlScrollBarLiveProc, (long) handp);
- if (vscroll == NULL) goto bail;
- HiliteControl(vscroll, 255);
- /* store our data */
- handp->hScroll = hscroll;
- handp->vScroll = vscroll;
- handp->isActive = false;
- handp->useSlowDrawing = drawSlow;
- /* readjust the coordinates and we're done... */
- HandyWindowSizeChanged(theWindow);
- GetIndString(title, kHandyWindowStrings, (handp->useSlowDrawing ? kHandyWindowSlowTitle : kHandyWindowTitle));
- SetWTitle(theWindow, title);
- ShowWindow(theWindow);
- return theWindow;
- bail:
- if (hscroll != NULL) DisposeControl(hscroll);
- if (vscroll != NULL) DisposeControl(vscroll);
- if (theWindow != NULL) DisposeWindow(theWindow);
- if (handp != NULL) DisposeHandyWindowRec(handp);
- return NULL;
- }
-
-
-
- /* HandyWindowCloseWindow closes the about box window.
- this routine deallocates any structures allocated
- by the OpenHandyWindow. */
- OSErr HandyWindowCloseWindow(WindowPtr theWindow) {
- HandyWindowPtr handp;
- handp = FindHandyWindow(theWindow);
- if (handp == NULL) return paramErr;
- DisposeControl(handp->hScroll);
- DisposeControl(handp->vScroll);
- DisposeWindow(handp->theWindow);
- DisposeHandyWindowRec(handp);
- return noErr;
- }
-
-
-
- /* CloseAllHandyWindows closes every handy window
- opened by calling OpenHandyWindow. */
- void CloseAllHandyWindows(void) {
- while (gHWFirst != NULL)
- HandyWindowCloseWindow(gHWFirst->theWindow);
- }
-
-
- /* HandyWindowUpdate should be called for update events
- directed at a handy window. It calls
- BeginUpdate and EndUpdate and does all of the
- drawing required to refresh the handy window. */
- OSErr HandyWindowUpdate(WindowPtr theWindow) {
- HandyWindowPtr handp;
- CGrafPtr windowGp;
- Rect contents, timerRect, wRect;
- /* set up our variables */
- handp = FindHandyWindow(theWindow);
- if (handp == NULL) return paramErr;
- /* set up the window */
- windowGp = GetWindowPort(theWindow);
- SetPort(windowGp);
- GetPortBounds(windowGp, &wRect);
- /* make sure the timer rectangle is part of the update region */
- SetRect( &timerRect, wRect.left, wRect.bottom-15, wRect.left+kTimerDisplayWidth, wRect.bottom+1);
- InvalWindowRect(theWindow, &timerRect);
- contents = wRect;
- contents.right -= 15;
- contents.bottom -= 15;
- /* set the window for drawing */
- BeginUpdate(theWindow);
- /* draw the controls and grow icon */
- Draw1Control(handp->hScroll);
- Draw1Control(handp->vScroll);
- DrawGrowIcon(theWindow);
- /* update the image */
- DrawHandyWindowImage(windowGp, &contents, handp);
- /* if the window is inactive, gray out the image */
- if ( ! handp->isActive)
- GrayOutBox(&contents);
- /* done drawing */
- EndUpdate(theWindow);
- return noErr;
- }
-
-
-
- /* HandyWindowActivate should be called for activate events
- directed at a handy window. */
- OSErr HandyWindowActivate(WindowPtr theWindow, Boolean activate) {
- HandyWindowPtr handp;
- /* verify the window is a handy window, get the variables */
- if ((handp = FindHandyWindow(theWindow)) == NULL) return paramErr;
- /* if the activate state is changing */
- if (handp->isActive != activate) {
- Rect bounds;
- CGrafPtr wPort;
- /* set the new activation state */
- handp->isActive = activate;
- wPort = GetWindowPort(theWindow);
- /* redraw as appropriate for new activation state */
- SetPort(wPort);
- GetPortBounds(wPort, &bounds);
- bounds.right -= 15;
- bounds.bottom -= 15;
- if (handp->isActive) {
- /* if the window is active, enable scroll bars and redraw contents */
- HiliteControl(handp->hScroll, 0);
- HiliteControl(handp->vScroll, 0);
- InvalWindowRect(theWindow, &bounds);
- } else {
- /* if the window is inactive, disable the scroll bars and gray out contents */
- HiliteControl(handp->hScroll, 255);
- HiliteControl(handp->vScroll, 255);
- GrayOutBox(&bounds);
- DrawGrowIcon(theWindow);
- DrawTimer(wPort, handp, 0);
- }
- }
- return noErr;
- }
-
-
-
- /* gPreviousScrollValue contains the last value of the scroll bar before the
- most recent scroll bar tracking operation. This value is used for tracking
- previous scroll values so we can determine the distance the display needs
- to be scrolled during live scrolling and indicator draggs. It is only used
- in when the click is in the kControlIndicatorPart part. */
- short gPreviousScrollValue = 0;
-
-
-
- /* WindowScrollBarProc is the callback procedure we pass to TrackControl
- during the handling of mouse clicks in scroll bars. It is also possible
- to call this routine specifying one of the part codes to obtain different
- scrolling behaviors (we do this for the arrow keys in the HandyWindowKey
- routine defined below). */
- static pascal void WindowScrollBarProc(ControlHandle theControl, short partCode) {
- short prev, max, next, *delta;
- short dh, dv, pageSize;
- HandyWindowPtr handp;
- Rect content;
- RgnHandle parttodraw, clipsave;
- CGrafPtr wPort;
- /* set up our local variables */
- handp = (HandyWindowPtr) GetControlReference(theControl);
- SetPort((wPort = GetWindowPort(handp->theWindow)));
- GetPortBounds(wPort, &content);
- content.right -= 15;
- content.bottom -= 15;
- /* initialize the horizontal and the vertical delta variables.
- dv and dh are used to store the vertical and horizontal distance
- the display is to be scrolled. */
- dh = dv = 0;
- /* calculate the page size and the delta variable
- we are going to be using. The delta variable we are
- changing and the page size depends on the scroll
- bar we are tracking. */
- if (theControl == handp->vScroll) {
- pageSize = content.bottom - content.top;
- delta = &dv;
- } else {
- pageSize = content.right - content.left;
- delta = &dh;
- }
- /* calculate the previous and next scroll bar
- positions. */
- switch (partCode) {
-
- /* for the up and down buttons, we scroll
- sizteen pixels */
- case kControlUpButtonPart:
- prev = GetControlValue(theControl);
- next = prev - 16;
- break;
- case kControlDownButtonPart:
- prev = GetControlValue(theControl);
- next = prev + 16;
- break;
-
- /* for the page up and page down areas, we scroll
- one page at a time (the width of the window for the
- horizontal scroll bar, and the height of the window for
- the vertical scroll bar. */
- case kControlPageUpPart:
- prev = GetControlValue(theControl);
- next = prev - pageSize;
- break;
- case kControlPageDownPart:
- prev = GetControlValue(theControl);
- next = prev + pageSize;
- break;
-
- /* kControlIndicatorPart will be passed to this routine
- during live scrolling operations or when the user is tracking
- the indicator part. Here, we calculate the distance the indicator
- has been moved using the gPreviousScrollValue global variable.
- note, we set the gPreviousScrollValue variable to the current
- scroll bar value so we can calculate the next delta the next time
- we are called. */
- case kControlIndicatorPart:
- prev = gPreviousScrollValue;
- gPreviousScrollValue = next = GetControlValue(theControl);
- break;
-
- /* if the user moves the mouse outside of the part that was
- originally clicked in, we may be called with a part code of zero.
- nothing to do here...*/
- default:
- return;
- }
- /* verify that our next value is in the allowable range of value */
- max = GetControlMaximum(theControl);
- if (next < 0) next = 0; else if (next > max) next = max;
- /* calculate the change. If there's no change, we're done.
- This is an important check as calling ScrollRect(.., 0, 0, xx)
- will crash on some systems. */
- *delta = prev - next;
- if (*delta == 0) return;
- /* set the new control bar value. if we're tracking the indicator
- next will already be the scroll value so there's no need to change
- it here, that's why there's the extra check */
- if (GetControlValue(theControl) != next)
- SetControlValue(theControl, next);
- /* save the current clipping region */
- GetClip((clipsave = NewRgn()));
- /* scroll the content area using our delta. This call to
- ScrollRect will set the region parttodraw to the new
- 'undrawn' area exposed by the operation */
- ScrollRectInBlack(&content, dh, dv, (parttodraw = NewRgn()));
- /* DrawHandyWindowImage will only perform drawing operations
- that are visible in the current clipping region, so to tell it that it does
- not have to draw the entire image, we set the clipping region to
- only the part that has been erased by the scrolling operation. */
- SetClip(parttodraw);
- /* draw the scrolled in area */
- DrawHandyWindowImage(GetWindowPort(handp->theWindow), &content, handp);
- /* restore the clipping region and clean up our storage */
- SetClip(clipsave);
- DisposeRgn(clipsave);
- DisposeRgn(parttodraw);
- }
-
-
-
- /* HandyWindowScrollUsingHand is called to scroll the window's view when the
- mouse is clicked in the window's contents. basically, this routine redraws the
- cursor as the 'grabbing hand' and then follows the mouse scrolling the contents
- and adjusting the scroll bar values as appropriate. */
- static void HandyWindowScrollUsingHand(HandyWindowPtr handp, Point where) {
- Point currentpt, lastpt, startpt;
- Point start, next, last, offset;
- RgnHandle clip, drawp;
- Rect mypin;
- Rect content;
- CGrafPtr wPort;
- /* set up our local variables */
- SetPort((wPort = GetWindowPort(handp->theWindow)));
- GetPortBounds(wPort, &content);
- content.right -= 15;
- content.bottom -= 15;
- startpt = lastpt = where;
- /* calculate the starting point */
- SetPt(&start, GetControlValue(handp->hScroll), GetControlValue(handp->vScroll));
- last = start;
- /* create a pin rectangle. We use this rectangle with the window manager
- PinRect routine to ensure the next value we calculate will always be
- within the allowable scrollable range. */
- SetRect(&mypin, 0, 0, GetControlMaximum(handp->hScroll)+1, GetControlMaximum(handp->vScroll)+1);
- clip = NewRgn();
- drawp = NewRgn();
- /* set the cursor to the grabbing hand */
- SetThemeCursor(kThemeClosedHandCursor);
- /* hilite the scroll bar indicators. This provides some visual feedback indicating
- the user is now scrolling using both scroll bar indicators at the same time. */
- HiliteControl(handp->hScroll, kControlIndicatorPart);
- HiliteControl(handp->vScroll, kControlIndicatorPart);
- /* while the mouse is being held down */
- while (StillDown()) {
- /* only recalculate when the mouse moves */
- GetMouse(¤tpt);
- if ( ! EqualPt(currentpt, lastpt)) {
- lastpt = currentpt;
- /* calculate the new scroll position based on cursor movement */
- next = startpt;
- SubPt(currentpt, &next);
- AddPt(start, &next);
- /* pin the new position into the maximum allowable range */
- (* (long*) &next) = PinRect(&mypin, next);
- /* calculate the delta from the last drawn position */
- offset = next;
- SubPt(last, &offset);
- /* only redraw and adjust scroll bar values if we
- are going to move the image.... */
- if (offset.h != 0 || offset.v != 0) {
- /* set the new scrolling position */
- SetControlValue(handp->hScroll, next.h);
- SetControlValue(handp->vScroll, next.v);
- last = next;
- /* save the clipping region */
- GetClip(clip);
- /* scroll the image. drawp will be set to the area exposed by
- the scrolling operation. */
- ScrollRectInBlack(&content, -offset.h, -offset.v, drawp);
- /* DrawHandyWindowImage will only perform drawing operations
- inside of the current clipping region. So, to speed up drawing, we
- set the clip region to the area exposed by the scroll. */
- SetClip(drawp);
- /* redraw the empty part of the screen */
- DrawHandyWindowImage(GetWindowPort(handp->theWindow), &content, handp);
- /* restore the clip region */
- SetClip(clip);
- }
- }
- }
- /* clean up our storage */
- DisposeRgn(clip);
- DisposeRgn(drawp);
- /* unhilite the scroll bar indicators */
- HiliteControl(handp->hScroll, 0);
- HiliteControl(handp->vScroll, 0);
- /* set the cursor back to the open hand */
- SetThemeCursor(kThemeOpenHandCursor);
- }
-
-
-
- /* HandyWindowScrollTo can be called to scroll the image to a particular
- location on screen. This routine attempts to scroll the image so that
- the location refered to by position is aligned with the top left corner of
- the window. Of course, the actual distance scrolled is pinned within
- the allowable range of scroll bar values. */
- OSErr HandyWindowScrollTo(WindowPtr theWindow, Point position) {
- HandyWindowPtr handp;
- Point next, last, offset;
- RgnHandle clip, drawp;
- Rect mypin;
- Rect content;
- CGrafPtr wPort;
- /* set up our local variables */
- handp = FindHandyWindow(theWindow);
- if (handp == NULL) return paramErr;
- SetPort((wPort = GetWindowPort(handp->theWindow)));
- GetPortBounds(wPort, &content);
- content.right -= 15;
- content.bottom -= 15;
- SetRect(&mypin, 0, 0, GetControlMaximum(handp->hScroll)+1, GetControlMaximum(handp->vScroll)+1);
- /* set the cursor to the grabbing hand */
- SetPt(&last, GetControlValue(handp->hScroll), GetControlValue(handp->vScroll));
- clip = NewRgn();
- drawp = NewRgn();
- next = position;
- (* (long*) &next) = PinRect(&mypin, next);
- /* calculate the delta from the last drawn position */
- offset = next;
- SubPt(last, &offset);
- /* if the new drawing position has changed, scroll and redraw... */
- if (offset.h != 0 || offset.v != 0) {
- /* set the new scrolling position */
- SetControlValue(handp->hScroll, next.h);
- SetControlValue(handp->vScroll, next.v);
- /* scroll the image */
- GetClip(clip);
- ScrollRectInBlack(&content, -offset.h, -offset.v, drawp);
- /* set the clip region to the area exposed by the scroll */
- SetClip(drawp);
- /* redraw the empty part of the screen */
- DrawHandyWindowImage(GetWindowPort(handp->theWindow), &content, handp);
- /* restore the clip region */
- SetClip(clip);
- }
- DisposeRgn(clip);
- DisposeRgn(drawp);
- return noErr;
- }
-
-
-
- /* HandyWindowActivate should be called for activate events
- directed at the about box window. */
- OSErr HandyWindowMouse(WindowPtr theWindow, Point where, short modifiers) {
- HandyWindowPtr handp;
- CGrafPtr wPort;
- Rect content, hscroll, vscroll;
- ControlHandle theControl;
-
- /* find the windows variables. If there are none, then it's
- not one of our windows. */
- if ((handp = FindHandyWindow(theWindow)) == NULL) return paramErr;
-
- /* set up locals, thePort, etc... */
- wPort = GetWindowPort(theWindow);
- SetPort(wPort);
- GetPortBounds(wPort, &content);
- content.right -= 15;
- content.bottom -= 15;
- theControl = NULL;
- /* check if its in a scroll bar. We do it this way incase other controls
- are being drawn in the window's content area. Since they are being
- drawn in a different coordinate system, when this call is made is may
- be possible that they overlap. */
- if (PtInRect(where, GetControlBounds(handp->hScroll, &hscroll)))
- theControl = handp->hScroll;
- else if (PtInRect(where, GetControlBounds(handp->vScroll, &vscroll)))
- theControl = handp->vScroll;
- /* if it was a scroll bar, then we handle the click as either an
- indicator click or as a regular part click. */
- if (theControl != NULL) {
- short partCode;
- static ControlActionUPP gMyActionProc = NULL;
- /* allocate our action procedure pointer. */
- if (gMyActionProc == NULL)
- gMyActionProc = NewControlActionProc(WindowScrollBarProc);
- /* find the part where the mouse was clicked. */
- partCode = TestControl(theControl, where);
- if (partCode == kControlIndicatorPart) {
- /* if we're dragging the indicator, then we set the cursor
- so it looks like we are grabbing the indicator. */
- SetThemeCursor(kThemeClosedHandCursor);
- /* save the previous scroll value. For live scrolling, this
- value is used inside of WindowScrollBarProc. */
- gPreviousScrollValue = GetControlValue(theControl);
- TrackControl(theControl, where, gMyActionProc);
- /* if the scroll bar does not support live scrolling, then this
- is where the actual scrolling will occur. Performing the scrolling
- at this point is 'the old way' kControlIndicatorPart (inThumb) drags
- were handled. It's not really necessary here, but it has been included
- for illustration. Without live scrolling, we would also call TrackControl
- with a NULL action procedure parameter. */
- if (gPreviousScrollValue != GetControlValue(theControl))
- WindowScrollBarProc(theControl, kControlIndicatorPart);
- /* restore the cursor to the 'open hand' since we are 'letting go'
- of the indicator. */
- SetThemeCursor(kThemeOpenHandCursor);
- } else if (partCode == kControlUpButtonPart || partCode == kControlDownButtonPart
- || partCode == kControlPageUpPart || kControlPageDownPart) {
- /* if it's another part, then we handle all of the scrolling in our
- tracking procedure. */
- TrackControl(theControl, where, gMyActionProc);
- }
- } else if (PtInRect(where, &content)) {
- HandyWindowScrollUsingHand(handp, where);
- }
- return noErr;
- }
-
-
-
- /* HandyWindowKey is called in response to key down events. Here, we dispatch
- special keys such as the arrows, page up, page down, home, and end to
- their equivalent actions using the scroll bars. */
- OSErr HandyWindowKey(WindowPtr theWindow, char key, short modifiers) {
- HandyWindowPtr handp;
- Point position;
- /* find the window's variables. if it has none, it's
- not one of our windows. */
- if ((handp = FindHandyWindow(theWindow)) == NULL) return paramErr;
- if ( ! handp->isActive) return paramErr;
- /* set up locals */
- switch (key) {
- case SOH: /* HOME KEY*/
- SetPt(&position, 0, 0);
- HandyWindowScrollTo(theWindow, position);
- break;
- case EOT: /* END KEY*/
- SetPt(&position, kImageWidth, kImageHeight);
- HandyWindowScrollTo(theWindow, position);
- break;
- case VT: /* PAGEUP KEY*/
- WindowScrollBarProc(handp->vScroll, kControlPageUpPart);
- break;
- case FF: /* PAGEDOWN KEY*/
- WindowScrollBarProc(handp->vScroll, kControlPageDownPart);
- break;
- case FS: /* LEFT ARROW KEY */
- WindowScrollBarProc(handp->hScroll, kControlUpButtonPart);
- break;
- case GS: /* RIGHT ARROW KEY */
- WindowScrollBarProc(handp->hScroll, kControlDownButtonPart);
- break;
- case RS: /* UP ARROW KEY */
- WindowScrollBarProc(handp->vScroll, kControlUpButtonPart);
- break;
- case US: /* DOWN ARROW KEY */
- WindowScrollBarProc(handp->vScroll, kControlDownButtonPart);
- break;
- default:
- return paramErr;
- break;
- }
- return noErr;
- }
-
-
- /* HandyWindowGetSlow returns the state of the handy window's drawing
- speed. For illustration, it is possible to set the drawing speed to either
- slow or fast. */
- OSErr HandyWindowGetSlow(WindowPtr theWindow, Boolean *drawnSlowly) {
- HandyWindowPtr handp;
- if ((handp = FindHandyWindow(theWindow)) == NULL) return paramErr;
- *drawnSlowly = handp->useSlowDrawing;
- return noErr;
- }
-
- /* HandyWindowSetSlow sets the state of the handy window's drawing
- speed and posts an update event so the contents will be re-drawn
- showing the new speed. For illustration, it is possible to set the
- drawing speed to either slow or fast. */
- OSErr HandyWindowSetSlow(WindowPtr theWindow, Boolean drawSlowly) {
- HandyWindowPtr handp;
- Rect contentRect;
- Str255 title;
- if ((handp = FindHandyWindow(theWindow)) == NULL) return paramErr;
- handp->useSlowDrawing = drawSlowly;
- GetPortBounds( GetWindowPort( theWindow), &contentRect);
- contentRect.right -= 15;
- contentRect.bottom -= 15;
- InvalWindowRect(theWindow, &contentRect);
- GetIndString(title, kHandyWindowStrings, (handp->useSlowDrawing ? kHandyWindowSlowTitle : kHandyWindowTitle));
- SetWTitle(theWindow, title);
- return noErr;
- }
-
-
- /* HandyWindowCursor is called when a handy window is the frontmost window and
- the HandySample application is the frontmost application. where is a point in
- the window's coordinates, and modifiers is the state of the modifier
- keys copied from the event record. mouseRgn is a handle to a region. If
- HandyWindowCursor sets the cursor, then it will also set this region to
- the region where it is appropriate for the cursor to remain as it has been
- set (in global coordinates). this region is appropriate for passing to WaitNextEvent
- in the mouse region parameter. */
- Boolean HandyWindowCursor(WindowPtr theWindow, Point where, short modifiers, RgnHandle mouseRgn) {
- HandyWindowPtr handp;
- CGrafPtr wPort;
- Rect contentRect;
- Point offset;
- /* find the window's variables. if it has none, it's
- not one of our windows. */
- if ((handp = FindHandyWindow(theWindow)) == NULL) return false;
- if ( ! handp->isActive) return false;
- /* set up locals */
- SetPort((wPort = GetWindowPort( theWindow)));
- /* calculate the window's origin in global coordinates */
- SetPt(&offset, 0, 0);
- LocalToGlobal( &offset);
- /* calculate the content rectangle */
- GetPortBounds( wPort, &contentRect);
- contentRect.right -= 15;
- contentRect.bottom -= 15;
- /* find the click location */
- if (PtInRect( where, &contentRect)) {
- /* if it's in the content area, then we use the open hand. */
- RectRgn(mouseRgn, &contentRect);
- OffsetRgn(mouseRgn, offset.h, offset.v);
- SetThemeCursor(kThemeOpenHandCursor);
- return true;
-
- /* for scroll bars, we call the routine SetScrollBarCursor defined
- in SampleUtils.h. That routine sets the cursor to a hand when it's
- over the scroll bar's indicator part. Otherwise it sets the cursor to
- a pointing finger. */
- } else if (SetScrollBarCursor(handp->hScroll, where, mouseRgn)) {
- OffsetRgn(mouseRgn, offset.h, offset.v);
- return true;
- } else if (SetScrollBarCursor(handp->vScroll, where, mouseRgn)) {
- OffsetRgn(mouseRgn, offset.h, offset.v);
- return true;
- }
- /* if the mouse isn't in our window, then we have nothing to say about it. */
- return false;
- }
-
-